iT邦幫忙

2022 iThome 鐵人賽

DAY 5
0

這篇我們來簡介如何使用 Markdown 語法撰寫文章,以及安裝 Contentlayer 將 Markdown 檔案轉換成文章。

這篇完整程式碼改動可以在這裡看:
https://github.com/Kamigami55/nextjs-tailwind-contentlayer-blog-starter/compare/day04-prepare...day05-markdown-contentlayer

我的個人網站裡也有此系列的好讀版,程式碼更易讀、也支援深色模式和側邊目錄,歡迎前往閱讀!


使用 Markdown 格式寫作

Markdown 是一個好讀又好寫的排版語法,在純文字檔中加入幾個特殊符號,就能標示出標題、連結、程式碼區塊、粗體、斜體、項目符號列點等等。

範例如下:

# 大標題
## H2 標題
### H3 標題

一段正常的文字,和 **粗體** 及 *斜體*。

[超連結](https://www.google.com/)

![圖片](https://i.imgur.com/oNtgi9e.png)

- 列點
- 列點 2

> Callout 引用區塊
> Tony Stark:「I am Iron Man」

> ```
> 程式碼區塊
> ```

Markdown 在開發者圈、寫作圈、筆記圈非常盛行,Github 的 README.md 或是各種留言框,都能使用 Markdown 語法。你現在看到的 iT 邦幫忙鐵人賽文章,也是用 Markdown 寫成的。現代筆記軟體如 Notion、CraftObsidianHackMD 等也都支援。

用 Markdown 寫作的主要優點是能讓我們專注於內容。它提供了數量剛好的格式語法,不至於少到無法排版地美觀,也不會多到讓我們花太多時間處理零碎排版。

再來是它好寫,修改格式只要簡單加個符號,手完全不用離開鍵盤,不會拖累你的打字速度。

最後因為他是純文字的,格式統一,很容易在各個平台間互相搬移。不需要過度擔心某個寫作平台停止維護後,自己的文章心血拿不回來的問題。

因此我們的部落格會使用 Markdown 來寫作!

Contentlayer,在 Next.js 裡處理 Markdown 文章

要在 Next.js 裡使用 Markdown 或 MDX(系列第 8 篇會介紹)寫作,有好幾個工具能實現:

這系列我們會採用 Contentlayer,它是裡面最年輕,開發體驗最好的解決方案。

Contentlayer

Contentlayer 是一個 JS 套件,功能是內容管理的 SDK,能將各種格式的文章,轉換成程式可讀的、Type-safe 的 JSON 格式。

Contentlayer 目前還在 beta 階段,支援了 Markdown 和 MDX 格式的文章來源,以及 Next.js 的整合。

Contentlayer 的用法是這樣的:我們首先要定義文章的格式、擁有的欄位及型別,接著在 pnpm dev 執行期間或 pnpm build 打包時,他就會將指定目錄所有文章,轉換成支援 TypeScript 的 JSON 格式,可直接在 Next.js 內 import 來渲染至畫面上。

Contentlayer 設定簡單,而且支援 live-reload,編輯文章時 Next.js 前端畫面也會同步更新,開發者體驗相當好。

安裝 Contentlayer

輸入指令安裝相關套件:

pnpn add contentlayer next-contentlayer
pnpm add -D esbuild

next.config.js 改名為 next.config.mjs,並修改內容如下:

import { withContentlayer } from 'next-contentlayer';

/** @type {import('next').NextConfig} */
const nextConfig = withContentlayer({
  reactStrictMode: true,
  swcMinify: true,
  eslint: {
    // Warning: This allows production builds to successfully complete even if
    // your project has ESLint errors.
    ignoreDuringBuilds: true,
  },
  typescript: {
    // Dangerously allow production builds to successfully complete even if
    // your project has type errors.
    ignoreBuildErrors: true,
  },
});

export default nextConfig;

修改 tsconfig.json

{
  "compilerOptions": {
    // ...
    "paths": {
      // ...
      "contentlayer/generated": ["./.contentlayer/generated"]
    }
  },
  "include": [
    // ...
    ".contentlayer/generated"
  ],
  // ...
}

新增 contentlayer.config.ts,定義 Post 這個資源以及我們需要的欄位:

import { defineDocumentType, makeSource } from './src/lib/contentLayerAdapter';

export const Post = defineDocumentType(() => ({
  name: 'Post',
  filePathPattern: `content/posts/**/*.md`,
  fields: {
    title: {
      type: 'string',
      required: true,
    },
    description: {
      type: 'string',
      required: true,
    },
    slug: {
      type: 'string',
      required: true,
    },
    date: {
      type: 'date',
      required: true,
    },
  },
  computedFields: {
    path: {
      type: 'string',
      resolve: (post) => `/posts/${post.slug}`,
    },
  },
}));

export default makeSource({
  contentDirPath: 'content',
  documentTypes: [Post],
});

新增 src/lib/contentLayerAdapter.js

import { allPosts, Post } from 'contentlayer/generated';
import {
  defineDocumentType,
  defineNestedType,
  makeSource,
} from 'contentlayer/source-files';

export { allPosts, defineDocumentType, defineNestedType, makeSource, Post };

修改 ESLint 設定,忽略 Contentlayer 相關警告

Contentlayer 的 import 模式,會被 ESLint 視為錯誤,但不影響功能,需要特別處理。

修改 .eslintrc.js,忽略 contentLayerAdapter.js 的 import 警告:

module.exports = {
  // ...
  settings: {
    // ...
    'import/ignore': ['contentLayerAdapter.js'],
  },
  // ...
};

修改 .gitignore.prettierignore,忽略 Contentlayer 會產生的檔案:

# ...

# Contentlayer
.contentlayer

修改 .eslintignore,忽略 Contentlayer 會產生的檔案,以及 contentLayerAdapter.js 的錯誤:

# ...
# Contentlayer
.contentlayer

# Ignore contentlayer eslint errors
contentLayerAdapter.js

這樣就完成 Contentlayer 設定了!

新增測試用 Markdown 文章

未來所有文章都放在 /content/posts/ 目錄裡,新增幾篇來測試吧!

新增 content/posts/20220830-sample-post.md

---
title: Sample post
description: My first post
slug: sample-post
date: 2022-08-30
type: Post
---

## This is my first sample post

Congratulations! You have created your first post.

新增 content/posts/20220831-markdown-demo.md

---
title: Markdown demo
description: This is a demo of Markdown
slug: markdown-demo
date: 2022-08-31
type: Post
---

## H2 title

### H3 title

Some content with [link](https://www.google.com)

驗證成果

執行 pnpm dev 啟動專案,看到 terminal 出現如下的訊息,就代表 Contentlayer 成功轉換完兩篇文章了:

Generated 2 documents in .contentlayer

console message

目前我們還沒在頁面上顯示文章,所以只能用這種方式驗證。

下一篇就會實際用上文章內容了!

References

小結&下一篇

我們了解了 Markdown 格式的文章寫作,也在 Next.js 安裝了 Contentlayer 處理 Markdown 檔案。

這篇完整程式碼改動可以在這裡看:
https://github.com/Kamigami55/nextjs-tailwind-contentlayer-blog-starter/compare/day04-prepare...day05-markdown-contentlayer

下一篇我們會開始實作基本首頁功能,顯示文章列表!


上一篇
ESLint、Prettier、TypeScript 等 Next.js 專案基礎設定 - Modern Next.js Blog 系列 #04
下一篇
首頁功能實作,加入 Contentlayer 文章列表 - Modern Next.js Blog 系列 #06
系列文
從零開始打造炫砲個人部落格,使用 Next.js、ContentLayer、i18next 等現代技術30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言